﻿namespace ElisVK.Controls
{
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Threading;

    public enum FilterMode
    {
        Instant,
        Delayed,
    }

    public class FilterTextBox : TextBox
    {
        public static readonly RoutedEvent FilterEvent =
            EventManager.RegisterRoutedEvent(
                "Filter",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(FilterTextBox));

        private static readonly DependencyProperty _labelTextProperty =
            DependencyProperty.Register(
                "LabelText",
                typeof(string),
                typeof(FilterTextBox));

        private static readonly DependencyProperty _labelTextColorProperty =
            DependencyProperty.Register(
                "LabelTextColor",
                typeof(Brush),
                typeof(FilterTextBox));

        private static readonly DependencyProperty _filterModeProperty =
            DependencyProperty.Register(
                "FilterMode",
                typeof(FilterMode),
                typeof(FilterTextBox),
                new PropertyMetadata(FilterMode.Instant));

        private static readonly DependencyPropertyKey _hasTextPropertyKey =
            DependencyProperty.RegisterReadOnly(
                "HasText",
                typeof(bool),
                typeof(FilterTextBox),
                new PropertyMetadata());

        private static readonly DependencyProperty _hasTextProperty = _hasTextPropertyKey.DependencyProperty;

        private static readonly DependencyPropertyKey _isMouseLeftButtonDownPropertyKey =
            DependencyProperty.RegisterReadOnly(
                "IsMouseLeftButtonDown",
                typeof(bool),
                typeof(FilterTextBox),
                new PropertyMetadata());

        private static readonly DependencyProperty _isMouseLeftButtonDownProperty = _isMouseLeftButtonDownPropertyKey.DependencyProperty;

        private static readonly DependencyProperty _filterEventTimeDelayProperty =
            DependencyProperty.Register(
                "FilterEventTimeDelay",
                typeof(Duration),
                typeof(FilterTextBox),
                new FrameworkPropertyMetadata(new Duration(new TimeSpan(0, 0, 0, 0, 500)), new PropertyChangedCallback(OnFilterEventTimeDelayChanged)));

        private readonly DispatcherTimer _filterEventDelayTimer;

        static FilterTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(FilterTextBox),
                new FrameworkPropertyMetadata(typeof(FilterTextBox)));
        }

        public FilterTextBox()
        {
            _filterEventDelayTimer = new DispatcherTimer { Interval = FilterEventTimeDelay.TimeSpan };
            _filterEventDelayTimer.Tick += OnFilterEventDelayTimerTick;
        }

        public event RoutedEventHandler Filter
        {
            add
            {
                AddHandler(FilterEvent, value);
            }

            remove
            {
                RemoveHandler(FilterEvent, value);
            }
        }

        public string LabelText
        {
            get
            {
                return (string)GetValue(_labelTextProperty);
            }

            set
            {
                SetValue(_labelTextProperty, value);
            }
        }

        public Brush LabelTextColor
        {
            get
            {
                return (Brush)GetValue(_labelTextColorProperty);
            }

            set
            {
                SetValue(_labelTextColorProperty, value);
            }
        }

        public FilterMode FilterMode
        {
            get
            {
                return (FilterMode)GetValue(_filterModeProperty);
            }

            set
            {
                SetValue(_filterModeProperty, value);
            }
        }

        public bool HasText
        {
            get
            {
                return (bool)GetValue(_hasTextProperty);
            }

            private set
            {
                SetValue(_hasTextPropertyKey, value);
            }
        }

        public Duration FilterEventTimeDelay
        {
            get
            {
                return (Duration)GetValue(_filterEventTimeDelayProperty);
            }

            set
            {
                SetValue(_filterEventTimeDelayProperty, value);
            }
        }

        public bool IsMouseLeftButtonDown
        {
            get
            {
                return (bool)GetValue(_isMouseLeftButtonDownProperty);
            }

            private set
            {
                SetValue(_isMouseLeftButtonDownPropertyKey, value);
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var iconBorder = GetTemplateChild("PART_IconBorder") as Border;

            if (iconBorder != null)
            {
                iconBorder.MouseLeftButtonDown += IconBorder_MouseLeftButtonDown;
                iconBorder.MouseLeftButtonUp += IconBorder_MouseLeftButtonUp;
                iconBorder.MouseLeave += IconBorder_MouseLeave;
            }
        }

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);

            HasText = Text.Length != 0;

            if (FilterMode == FilterMode.Instant)
            {
                _filterEventDelayTimer.Stop();
                _filterEventDelayTimer.Start();
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Escape && FilterMode == FilterMode.Instant)
            {
                Text = string.Empty;
            }
            else if ((e.Key == Key.Return || e.Key == Key.Enter) && FilterMode == FilterMode.Delayed)
            {
                RaiseFilterEvent();
            }
            else
            {
                base.OnKeyDown(e);
            }
        }

        private static void OnFilterEventTimeDelayChanged(
            DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var stb = o as FilterTextBox;

            if (stb != null)
            {
                stb._filterEventDelayTimer.Interval = ((Duration)e.NewValue).TimeSpan;
                stb._filterEventDelayTimer.Stop();
            }
        }

        private void OnFilterEventDelayTimerTick(object o, EventArgs e)
        {
            _filterEventDelayTimer.Stop();
            RaiseFilterEvent();
        }

        private void IconBorder_MouseLeftButtonDown(object obj, MouseButtonEventArgs e)
        {
            IsMouseLeftButtonDown = true;
        }

        private void IconBorder_MouseLeftButtonUp(object obj, MouseButtonEventArgs e)
        {
            if (!IsMouseLeftButtonDown) return;

            if (HasText && FilterMode == FilterMode.Instant)
            {
                Text = string.Empty;
            }

            if (HasText && FilterMode == FilterMode.Delayed)
            {
                RaiseFilterEvent();
            }

            IsMouseLeftButtonDown = false;
        }

        private void IconBorder_MouseLeave(object obj, MouseEventArgs e)
        {
            IsMouseLeftButtonDown = false;
        }

        private void RaiseFilterEvent()
        {
            var args = new RoutedEventArgs(FilterEvent);

            RaiseEvent(args);
        }
    }
}
